package com.lds.erp.common;

import java.io.*;
import javax.servlet.http.HttpServletRequest;

import com.lds.erp.common.sms.SmsVerifyCodeFacade;
import com.lds.erp.mch.mch.MchInfoFacade;
import com.lds.erp.mch.mch.result.MchInfoResult;
import com.lds.erp.mch.mch.result.WarehouseAreaResult;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dph.common.utils.core.exception.BizError;
import com.dph.common.utils.utils.AppUtils;
import com.dph.common.utils.utils.StringUtil;
import com.dph.common.utils.utils.sms.NetEaseSendResult;
import com.lds.erp.base.JsonResult;
import com.lds.erp.common.ao.LoginAO;
import com.lds.erp.common.ao.SMSAO;

import com.lds.erp.common.sms.order.SMSSentOrder;
import com.lds.erp.common.sms.order.VerifyCodeOrder;
import com.lds.erp.common.sms.result.VerifyResult;
import com.lds.erp.common.util.AccountCache;
import com.lds.erp.common.util.AccountUtils;
import com.lds.erp.common.vo.LoginVO;
import com.lds.erp.common.vo.MchVO;
import com.lds.erp.configuration.ConfigProperty;
import com.lds.erp.enums.ClientSourceEnum;
import com.lds.erp.gateway.interceptor.SignValidInterceptor;

import com.lds.erp.mch.mch.info.MchInfoInfo;
import com.lds.erp.mch.mch.order.MchInfoSignInOrder;
import com.lds.erp.mch.mch.order.WeiXiLoginOrder;
import com.lds.erp.mch.mch.result.MchInfoSignInResult;
import com.lds.erp.util.EncryUtil;
import com.lds.erp.util.JsonUtils;
import com.lds.erp.util.QiNiuTokenVO;
import com.lds.erp.util.SpringRequestUtils;
import com.lds.erp.util.Uptoken;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;


import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;

/**
 * @author senilon
 * @apiNote 免登的公共服务
 * @date 2018/9/18 下午7:02
 */
@RestController
@RequestMapping("/api/common/account/")
@Api(value = "登录相关的接口", description = "无需登录即可访问的接口", tags = { "登录相关" })
public class CommonAccountController {
	private final static Logger log = LoggerFactory.getLogger(CommonAccountController.class);

	@Autowired
	private ConfigProperty configProperty;

	@Reference(version = "1.0")
	private MchInfoFacade mchInfoFacade;

	@Reference(version = "1.0")
	private SmsVerifyCodeFacade smsVerifyCodeService;


	@GetMapping("update_mchLastLoginTime")
	@ApiOperation(value = "更新登录时间", notes = "更新登录时间")
	public JsonResult updatemchLastLoginTime(String mchId) {

		int result = 0;

		if (mchId  != null) {
			result = mchInfoFacade.updatemchLastLoginTime(mchId);
		}
		else
		{
			return JsonUtils.fail("mch_id不能为空");
		}

		if (result > 0)
		{
			return JsonUtils.success("成功修改数量:" + result);
		}
		else
		{
			return JsonUtils.fail("操作失败");
		}
	}


	@GetMapping("check_area")
	@ApiOperation(value = "区域匹配", notes = "区域匹配")
	public JsonResult checkArea(String district) {

		WarehouseAreaResult result = null;
		if (district  != null) {
			result = mchInfoFacade.checkArea(district);
		}
		else
		{
			return JsonUtils.fail("districtId不能为空");
		}

        if (result.getCode().equalsIgnoreCase("1"))
		{
			return JsonUtils.success(result);
		}
        else
		{
			return JsonUtils.fail("绑定区域暂未开放，暂时将你改为渝北区，如有问题联系客服修改",result);
		}



	}


	@GetMapping("update_mchLastDistrict")
	@ApiOperation(value = "更新上次选择区域", notes = "更新上次选择区域")
	public JsonResult<MchInfoResult> updatemchLastDistrict(String mchId,Integer districtId,String districtStr) {

		MchInfoResult result = new MchInfoResult();

		if (mchId  != null) {
			result = mchInfoFacade.updatemchLastDistrict(mchId,districtId,districtStr);
		}
		else
		{
			return JsonUtils.fail("mch_id不能为空");
		}


		return JsonUtils.success(result);


	}


	@GetMapping("update_mchInviteRelation")
	@ApiOperation(value = "", notes = "")
	public JsonResult updateMchInviteRelation(String mchId,String inviteCode) {

		int result = 0;

		if (mchId  != null  && inviteCode  != null) {
			result = mchInfoFacade.updateMchInviteRelation(mchId,inviteCode);
		}
		else
		{
			return JsonUtils.fail("参数不能为空");
		}

		if (result == -4)
		{
			return JsonUtils.fail("该用户邀请码已经存在");
		}
		else if (result == -3)
		{
			return JsonUtils.fail("该用户不存在");
		}
        else if (result == -2)
		{
			return JsonUtils.fail("该邀请码不存在");
		}
  		if (result > 0)
		{
			return JsonUtils.success("操作成功.");
		}
		else
		{
			return JsonUtils.fail("操作失败");
		}
	}

	public class InviteCodeResult {
		private String inviteCode;

		public String getInviteCode() {
			return inviteCode;
		}

		public void setInviteCode(String inviteCode) {
			this.inviteCode = inviteCode;
		}
	}


	@GetMapping("getInviteCodeByPhone")
	@ApiOperation(value = "", notes = "")
	public JsonResult getInviteCodeByPhone(String phone) {

		String result = null;
		InviteCodeResult inviteCodeResult = new InviteCodeResult();
		if (phone  != null) {
			result = mchInfoFacade.getInviteCodeByPhone(phone);
			inviteCodeResult.setInviteCode(result);
		}
		return JsonUtils.success(inviteCodeResult);
	}


	private JsonResult validateGetSign(HttpServletRequest request) throws IOException {
		// 移动端登录
		String appStr = request.getHeader("app");
		AppEnum app = AppEnum.getEnumByCode(appStr);
		if (ObjectUtils.isEmpty(app)) {
			return JsonUtils.fail("未接入的移动端[" + appStr + "]");
		}

		// 移动端验签
		if (!SignValidInterceptor.validGetSign(request)) {
			return JsonUtils.fail(SignValidInterceptor.FAIL_MESSAGE);
		}
		return null;
	}

	@GetMapping("mobile_code")
	@ApiOperation(value = "手机登录验证码(senilon)", notes = "mobile 必传")
	public JsonResult mobileCode(SMSAO smsao, HttpServletRequest request) throws IOException {
		// 校验
		JsonResult appStr1 = validateGetSign(request);
		if (appStr1 != null) {
			return appStr1;
		}

		SMSSentOrder order = new SMSSentOrder();
		order.setSerialNo(AppUtils.newOrderNo());
		order.setMobile(smsao.getMobile());
		order.setType(SMSBusinessTypeEnum.LOGIN);

		NetEaseSendResult result = smsVerifyCodeService.sendVerifyCode(order);
		return result.isSuccess() ? JsonUtils.success("获取成功,请查看手机!" + result.getCode())
				: JsonUtils.fail(result.getMsg());
	}

	@GetMapping("check_token")
	@ApiOperation(value = "token校验(senilon)", notes = "token校验,除开发者模式以外,其他模式token必须放在head中访问")
	public JsonResult verifyLogin(@RequestParam String token, HttpServletRequest request) throws IOException {
		// 移动端验签
		if (!SignValidInterceptor.validPostSign(request)) {
			return JsonUtils.fail(SignValidInterceptor.FAIL_MESSAGE);
		}
		// token检测
		AccountCache cache = AccountUtils.getAccount(token);
		if (ObjectUtils.isEmpty(cache)) {
			return JsonUtils.fail("401", "请登陆后再试!", null);
		}

		return JsonUtils.success("校验通过");

	}

	@GetMapping("exit")
	@ApiOperation(value = "退出登录(senilon)", notes = "token校验,除开发者模式以外,其他模式token必须放在head中访问")
	public JsonResult exit(HttpServletRequest request) throws IOException {
		// 校验
		JsonResult appStr1 = validateGetSign(request);
		if (appStr1 != null) {
			return appStr1;
		}

		// 获取token
		String token = request.getHeader("token");
		// 开发者模式允许从url中获取token
		if (StringUtil.isBlank(token) && configProperty.getDeveloperMode()) {
			token = request.getParameter("token");
		}
		// 获取请求来源
		ClientSourceEnum client = SpringRequestUtils.getClientSource(request);
		AccountCache cache = AccountUtils.getAccount(token);
		if (!ObjectUtils.isEmpty(cache)) {
			AccountUtils.remove(token);
		}
		return JsonUtils.success("退出成功!");
	}

	@PostMapping("login")
	@ApiOperation(value = "登录(senilon)", notes = "用户登录(如果没有帐号默认创建一个)。后续接口都需要在header中放入token,来源于登录后的mchToken。另外所有接口都需要在header中传入参数app值为固定的MCHMP")
	public JsonResult<LoginVO> accountLogin(@RequestBody LoginAO ao, HttpServletRequest request) throws IOException {
		MchInfoSignInOrder order = new MchInfoSignInOrder();
		order.setSerialNo(AppUtils.newNo());
		order.setPassword(ao.getPassword());
		order.setMobile(ao.getAccount());
		order.setDeviceId(ao.getDeviceId());
		order.setLoginType(ao.getMchLoginType());
		order.setMchName(ao.getMchName());
		order.setMchImage(ao.getMchImage());
		order.setInviteCode(ao.getInviteCode());
		JsonResult<LoginVO> appStr1 = validatePostSign(request);
		if (appStr1 != null) {
			return appStr1;
		}

		// 移动端登录
		String appStr = request.getHeader("app");
		AppEnum app = AppEnum.getEnumByCode(appStr);
		log.info("接入是哪一端:{}", app.getCode());
		order.setAppEnum(app);

		// 如果小程序登录成功,则需要自定义一些登录状态给前端
		if (AppEnum.MCHMP.getCode().equals(app.getCode())) {
			WeiXiLoginOrder weiXiLoginOrder = getWeixinLogin(ao.getWeiXinCode());
			order.setWeiXiLoginOrder(weiXiLoginOrder);
		}

		MchInfoSignInResult result = null;
		// 特殊帐号登录不受限制，假装登录
		String ingore = "18523036721,15000000000,15000000001,15000000002";
		if (ingore.indexOf(order.getMobile()) > -1) {
			// 特殊帐号重置登录方式
			order.setSpecialAccount(YNEnum.Y);
			order.setLoginType(MchLoginTypeEnum.PASSWD);
			result = mchInfoFacade.findMchInfoSignIn(order);
			if (result.isFail()) {
				return JsonUtils.fail(result.getMessage());
			}
		} else {
			// 手机验证码登录
			if (MchLoginTypeEnum.SMSCODE.equals(ao.getMchLoginType())) {
				// 验证码验证是否成功
				VerifyCodeOrder verifyCodeOrder = new VerifyCodeOrder();
				verifyCodeOrder.setPhone(ao.getAccount());
				verifyCodeOrder.setCode(ao.getPassword());
				verifyCodeOrder.setSerialNo(order.getSerialNo());
				VerifyResult verifyResult = smsVerifyCodeService.doVerifyCode(verifyCodeOrder);
				if (verifyResult.isSuccess()) {
					result = mchInfoFacade.findMchInfoSignIn(order);
				} else {
					return JsonUtils.fail(verifyResult.getMsg());
				}
			}
			else if (MchLoginTypeEnum.WECHAT.equals(ao.getMchLoginType())) {
				result = mchInfoFacade.findMchInfoSignIn(order);
			}
			// 账密登录
			else {
				result = mchInfoFacade.findMchInfoSignIn(order);
				if (result.isFail()) {
					return JsonUtils.fail(result.getMessage());
				}
			}
		}
		return buildLoginVO(result, order);
	}

	@GetMapping("getMchBaseInfo")
	public JsonResult<MchVO> getMchBaseInfo(@RequestParam String mobile){
		MchInfoSignInOrder order = new MchInfoSignInOrder();
		order.setMobile(mobile);
		MchInfoSignInResult result = null;
		result = mchInfoFacade.getMchBaseInfo(order);
		MchVO mchVO = new MchVO();
		if (result.isSuccess()) {
			BeanUtils.copyProperties(result.getMchInfoInfo(), mchVO);
		}
		return result.isSuccess() ? JsonUtils.success(mchVO)
				: JsonUtils.fail(result.getMessage());
	}

	@GetMapping("getSessionkey")
	public JsonResult getSessionkeyInfo(String weiXinCode,String encryptedData, String iv) throws IOException {

		String result= null;
		JSONObject jsonObject = null;
		try {
			WeiXiLoginOrder weiXiLoginOrder = getSessionKey(weiXinCode);
			result= decrypt(weiXiLoginOrder.getSessionKey(),iv,encryptedData);
			jsonObject = JSON.parseObject(result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return JsonUtils.success(jsonObject);
	}


	public static String decrypt(String sessionKey,String ivData, String encrypData) throws Exception {
		byte[] encData = Base64.decodeBase64(encrypData);
		byte[] iv = Base64.decodeBase64(ivData);
		byte[] key = Base64.decodeBase64(sessionKey);
		AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
		cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
		//解析解密后的字符串
		return new String(cipher.doFinal(encData), "UTF-8");
	}




	private JsonResult<LoginVO> validatePostSign(HttpServletRequest request) throws IOException {
		// 移动端登录
		String appStr = request.getHeader("app");
		AppEnum app = AppEnum.getEnumByCode(appStr);
		if (ObjectUtils.isEmpty(app)) {
			String allow = AppEnum.MCHMP.getCode();
			return JsonUtils.fail("未接入的移动端[" + appStr + "],目前允许接入的移动端为:" + allow);
		}

		// 移动端验签
		if (!SignValidInterceptor.validPostSign(request)) {
			return JsonUtils.fail(SignValidInterceptor.FAIL_MESSAGE);
		}
		return null;
	}

	private JsonResult<LoginVO> buildLoginVO(MchInfoSignInResult result, MchInfoSignInOrder order) {
		// 账号密码登录成功,是否开启短信验证
		// 老系统直接透传
		if (result.isSuccess()) {
			LoginVO loginVO = new LoginVO();
			// 缓存信息
			AccountCache accountCache = new AccountCache();
			MchInfoInfo mchInfoInfo = result.getMchInfoInfo();
			BeanUtils.copyProperties(mchInfoInfo, accountCache);
			AccountUtils.cacheAccount(accountCache);

			MchVO mchVO = new MchVO();
			BeanUtils.copyProperties(mchInfoInfo, mchVO);
			mchVO.setMchOpenid(EncryUtil.encrypt(mchVO.getMchOpenid()));
			mchVO.setImageDomainUrl(configProperty.getQiniuImageDomain());
			loginVO.setMchVO(mchVO);
			return JsonUtils.success("登录成功", loginVO);
		}else{
			LoginVO loginVO = new LoginVO();
			MchVO mchVO = new MchVO();
			BeanUtils.copyProperties(result.getMchInfoInfo(), mchVO);
			loginVO.setMchVO(mchVO);
			return JsonUtils.fail(result.getMessage(),loginVO);
		}

	}

	// @GetMapping("findWeiXiLoginBind")
	// @ApiOperation(value = "查找微信是否与商户绑定(senilon)", notes =
	// "用户登录,是否与商户绑定，进入小程序第一个接口")
	// public JsonResult<MchWeiXinVO> findWeiXiLoginBind(@RequestParam(value =
	// "weiXinCode") String weiXinCode) {
	// WeiXiLoginOrder weiXiLoginOrder = getWeixinLogin(weiXinCode);
	// MchWeiXinVO mchWeiXinVO = new MchWeiXinVO();
	// if (weiXiLoginOrder != null) {
	// MchInfoWeiXinLoginBindResult result =
	// mchInfoFacade.findWeiXiLoginBind(weiXiLoginOrder);
	// BeanUtils.copyProperties(result, mchWeiXinVO);
	// // 加密处理，使用时需解密
	// mchWeiXinVO.setMchOpenid(EncryUtil.encrypt(weiXiLoginOrder.getMchOpenid()));
	// return JsonUtils.success(mchWeiXinVO);
	// }
	// return JsonUtils.fail("查找失败");
	// }

	private WeiXiLoginOrder getWeixinLogin(String code) {
		String appId = configProperty.getWeiXinAppId();
		String secret = configProperty.getWeiXinSecret();
		String authUrl = configProperty.getWeiXinAuthCode();
		// 转换url
		String url = String.format(authUrl, appId, secret, code);
		// 发送请求给微信后端
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpGet httpGet = new HttpGet(url);
		InputStream inputStream = null;
		CloseableHttpResponse httpResponse = null;
		WeiXiLoginOrder weiXiLoginOrder = new WeiXiLoginOrder();
		try {
			httpResponse = httpClient.execute(httpGet);
			HttpEntity entity = httpResponse.getEntity();
			inputStream = entity.getContent();
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
			String line = "";
			String openId = null;
			String unionId = null;
			while ((line = bufferedReader.readLine()) != null) {
				JSONObject jsonObject = JSON.parseObject(line);
				log.info("小程序返回参数:{}", jsonObject.toJSONString());
				openId = jsonObject.getString("openid");
				unionId = jsonObject.getString("unionid");
				if (StringUtils.isEmpty(openId)) {
					throw new BizError("小程序登录失败,请联系后台管理人员查看问题!");
				}
			}
			weiXiLoginOrder.setMchOpenid(openId);
			weiXiLoginOrder.setUnionId(unionId);
		} catch (IOException e) {
			log.error("error", e);
			throw new BizError("小程序登录失败,请联系后台管理人员查看问题!");
		}
		return weiXiLoginOrder;
	}



	private WeiXiLoginOrder getSessionKey(String code) {
		String appId = configProperty.getWeiXinAppId();
		String secret = configProperty.getWeiXinSecret();
		String authUrl = configProperty.getWeiXinAuthCode();
		// 转换url
		String url = String.format(authUrl, appId, secret, code);

		// 发送请求给微信后端
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpGet httpGet = new HttpGet(url);
		InputStream inputStream = null;
		CloseableHttpResponse httpResponse = null;
		WeiXiLoginOrder weiXiLoginOrder = new WeiXiLoginOrder();
		try {
			httpResponse = httpClient.execute(httpGet);
			HttpEntity entity = httpResponse.getEntity();
			inputStream = entity.getContent();
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
			String line = "";
			String openId = null;
			String unionId = null;
			String sessionKey = null;
			while ((line = bufferedReader.readLine()) != null) {
				JSONObject jsonObject = JSON.parseObject(line);
				log.info("小程序返回参数:{}", jsonObject.toJSONString());
				openId = jsonObject.getString("openid");
				unionId = jsonObject.getString("unionid");
				sessionKey = jsonObject.getString("session_key");
				if (StringUtils.isEmpty(openId)) {
					throw new BizError("没有获取到session_key");
				}
			}
			weiXiLoginOrder.setMchOpenid(openId);
			weiXiLoginOrder.setUnionId(unionId);
			weiXiLoginOrder.setSessionKey(sessionKey);
		} catch (IOException e) {
			log.error("error", e);
			throw new BizError("获取session_key失败");
		}
		return weiXiLoginOrder;
	}


	@ApiOperation(value = "七牛上传图片时token及图片地址获取", notes = "七牛上传图片时token及图片地址获取")
    @GetMapping("qiniu_token")
    public JsonResult<QiNiuTokenVO> getQiNiuB2ERPToken() {
    	QiNiuTokenVO token = Uptoken.getUpToken();
        return JsonUtils.success(token);
    }


	public static String LoadContentByPath(String path) throws IOException {
		InputStream is = new FileInputStream(path);
		BufferedReader in = new BufferedReader(new InputStreamReader(is));
		StringBuffer buffer = new StringBuffer();
		String line = "";
		while ((line = in.readLine()) != null){
			buffer.append(line);
		}
		return buffer.toString();

	}


	@ApiOperation(value = "区域json文件", notes = "区域json文件")
	@GetMapping("get_area")
	public JsonResult getArea() {
		String path = "d:/area.json";
		String areas = "";
		try {
			areas = LoadContentByPath(path);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return JsonUtils.success("",areas);
	}


	@ApiOperation(value = "区域json文件", notes = "区域json文件")
	@GetMapping("get_area_l")
	public JsonResult getArea_l() {
		//String path = "d:/area.json";
		String path = "/alidata/json/area.json";
		String areas = "";
		try {
			areas = LoadContentByPath(path);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return JsonUtils.success("",areas);
	}

}
